home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / misc / sci / ephem_src_4_28.lha / watch.c < prev   
C/C++ Source or Header  |  1992-04-17  |  12KB  |  425 lines

  1. /* these functions allow you to watch the sky or the solar system via a
  2.  * simple character-graphics representation on the screen. 
  3.  * the interaction starts by using the current time. then control with
  4.  *    END returns to table form; or
  5.  *    RETURN advances time by one StpSz; or
  6.  *    h advances once by 1 hour; or
  7.  *    d advances once by 24 hours (1 day); or
  8.  *    w advances once by 7 days (1 week); or
  9.  *    any other key free runs by StpSz until any key is hit.
  10.  */
  11.  
  12. #include <stdio.h>
  13. #include <math.h>
  14. #include "astro.h"
  15. #include "circum.h"
  16. #include "screen.h"
  17.  
  18. #define    SSZCOL    1        /* column to show solar system z coords */
  19. #define    PARK_ROW    1    /* cursor park loc after each screen */
  20. #define    PARK_COL    NC    /* cursor park loc after each screen */
  21.  
  22. #define    DOMESKY        0    /* flags for watch_sky() */
  23. #define    ALTAZSKY    1    /* flags for watch_sky() */
  24.  
  25. #define    SKYACC    3600.    /* desired sky plot accuracy, in arc seconds */
  26. #define    SSACC    3600.    /* desired solar system plot accuracy, in arc secs */
  27.  
  28. /* macros to convert row(col) in range 1..NR(1..NC) to fraction in range 0..1 */
  29. #define    NEARONE        0.9999999
  30. #define    r2fr(r)        (((r)-1)/(NEARONE*NR)+1/NC/2)
  31. #define    c2fc(c)        (((c)-1)/(NEARONE*NC)+1/NC/2)
  32. #define    fr2r(fr)    ((int)((fr)*(NEARONE*NR))+1)
  33. #define    fc2c(fc)    ((int)((fc)*(NEARONE*NC))+1)
  34.  
  35. /* single-character tag for each body.
  36.  * order must match the #defines in astro.h and screen.h additions.
  37.  */
  38. static char body_tags[] = "evmjsunpSMxy";
  39.  
  40. /* multiple and single loop prompts */
  41. static char frprompt[] = "Running... press any key to stop.";
  42. static char qprompt[]  =
  43. "q to quit, RETURN/h/d/w to step by StpSz/hr/day/wk, or any other to freerun";
  44.  
  45. /* used to locate, record and then erase last plotted chars */
  46. typedef struct {
  47.     double l_fr, l_fc;    /* 2d coords as 0..1 (upper left corner is (0,0)) */
  48.     int     l_r, l_c;    /* screen 2d coords (upper left corner is [1,1]) */
  49.     char l_tag;        /* char to use to print on screen */
  50. } LastDraw;
  51.  
  52. static int trails;    /* !0 if want to leave trails */
  53.  
  54. watch (np, tminc, wbodies)
  55. Now *np;    /* time now and on each step */
  56. double tminc;    /* hrs to increment time by each step */
  57. int wbodies;    /* each bit is !=0 if want that body */
  58. {
  59.     static char *flds[4] = {
  60.         "Sky dome", "Alt/az sky", "Solar system"
  61.     };
  62.     static int fn;    /* begin with 0, then remember for next time */
  63.     int didone = 0;
  64.  
  65.     while (1) {
  66.         int nf;
  67.         flds[3] = trails ? "Leave trails" : "No trails";
  68.         if ((nf = popup (flds, fn, 4)) < 0)
  69.         break;
  70.         fn = nf;
  71.         switch (nf) {
  72.         case 0: watch_sky (DOMESKY, np, tminc, wbodies); didone = 1; break;
  73.         case 1: watch_sky (ALTAZSKY, np, tminc, wbodies); didone = 1; break;
  74.         case 2: watch_solarsystem (np, tminc, wbodies); didone = 1; break;
  75.         case 3: trails ^= 1; break;
  76.         }
  77.     }
  78.  
  79.     if (didone)
  80.         redraw_screen(2);
  81. }
  82.  
  83. /* full alt/az or dome sky view (like the popular astro mags).
  84.  * alt/az: north is at left and right of screen, south at center.
  85.  *   0 elevation is at bottom of screen, zenith at the top.
  86.  * dome: east is left, north is up.
  87.  */
  88. static
  89. watch_sky (style, np, tminc, wbodies)
  90. int style;    /* DOMESKY or ALTAZSKY */
  91. Now *np;    /* time now and on each step */
  92. double tminc;    /* hrs to increment time by each step */
  93. int wbodies;    /* each bit is !=0 if want */
  94. {
  95.     static char east[] = "East";
  96.     static char west[] = "West";
  97.     static char north[] = "North";
  98.     static char south[] = "South";
  99.     double tminc0 = tminc;    /* remember the original */
  100.     /* two draw buffers so we can leave old up while calc new then
  101.      * erase and draw in one quick operation. always calc new in newp
  102.      * buffer and erase previous from lastp. buffers alternate roles.
  103.      */
  104.     LastDraw ld0[NOBJ], ld1[NOBJ], *lp, *lastp = ld0, *newp = ld1;
  105.     int nlast = 0, nnew;
  106.     int once = 1;
  107.     double lmjd, tmp;
  108.     Sky s;
  109.     int p;
  110.  
  111.     /* clear screen and put up the permanent labels */
  112.     c_erase();
  113.     if (style == DOMESKY) {
  114.         double a;
  115.         for (a = 0.0; a < 2*PI; a += PI/8)
  116.         f_char (fr2r(.5-sin(a)/2.),
  117.             fc2c(.5+cos(a)/2./ASPECT) + ((a>PI/2 && a<3*PI/2) ? -1 : 1),
  118.             '*');
  119.         f_string (fr2r(.5), fc2c(.5-.5/ASPECT)-7, "East");
  120.         f_string (fr2r(1.), fc2c(.5)-2, south);
  121.         f_string (fr2r(.5), fc2c(.5+.5/ASPECT)+4, "West");
  122.         f_string (2, NC/2-2, north);
  123.     } else {
  124.         f_string (NR, 1, north);
  125.         f_string (NR, NC/4, east);
  126.         f_string (NR, NC/2, south);
  127.         f_string (NR, 3*NC/4, west);
  128.         f_string (NR, NC-5, north);   /* -1 more to avoid scrolling */
  129.         f_string (2, NC/2-3, "Zenith");
  130.     }
  131.     f_string (2, 1, tznm);
  132.     f_string (3, 1, "LST");
  133.  
  134.     while (1) {
  135.         if (once)
  136.         print_updating();
  137.  
  138.         /* calculate desired stuff into newp[] */
  139.         nnew = 0;
  140.         for (p = nxtbody(-1); p != -1; p = nxtbody(p))
  141.         if (wbodies & (1<<p)) {
  142.             (void) body_cir (p, SKYACC, np, &s);
  143.             if (s.s_alt > 0.0) {
  144.             LastDraw *lnp = newp + nnew;
  145.             if (style == DOMESKY) {
  146.                 tmp = 0.5 - s.s_alt/PI;
  147.                 lnp->l_fr = 0.5 - tmp*cos(s.s_az);
  148.                 lnp->l_fc = 0.5 - tmp*sin(s.s_az)/ASPECT;
  149.             } else {
  150.                 lnp->l_fr = 1.0 - s.s_alt/(PI/2);
  151.                 lnp->l_fc = s.s_az/(2*PI);
  152.             }
  153.             lnp->l_tag = body_tags[p];
  154.             nnew++;
  155.             }
  156.         }
  157.         set_screencoords (newp, nnew);
  158.  
  159.         /* unless we want trails,
  160.          * erase any previous tags (in same order as written) from lastp[].
  161.          */
  162.         if (!trails)
  163.         for (lp = lastp; --nlast >= 0; lp++)
  164.             f_char (lp->l_r, lp->l_c, ' ');
  165.  
  166.         /* print LOCAL time and date we will be using */
  167.         lmjd = mjd - tz/24.0;
  168.         f_time (2, 5, mjd_hr(lmjd));
  169.         f_date (2, 14, mjd_day(lmjd));
  170.         now_lst (np, &tmp);
  171.         f_time (3, 5, tmp);
  172.  
  173.         /* now draw new stuff from newp[] and park the cursor */
  174.         for (lp = newp; lp < newp + nnew; lp++)
  175.         f_char (lp->l_r, lp->l_c, lp->l_tag);
  176.         c_pos (PARK_ROW, PARK_COL);
  177.         fflush (stdout);
  178.  
  179.         /* swap new and last roles and save new count */
  180.         if (newp == ld0)
  181.         newp = ld1, lastp = ld0;
  182.         else
  183.         newp = ld0, lastp = ld1;
  184.         nlast = nnew;
  185.  
  186.         if (!once)
  187.         slp_sync();
  188.  
  189.         if (once || (chk_char()==0 && read_char()!=0)) {
  190.         if (readwcmd (tminc0, &tminc, &once) < 0)
  191.             break;
  192.         }
  193.  
  194.         /* advance time */
  195.         inc_mjd (np, tminc);
  196.     }
  197. }
  198.  
  199. /* solar system view, "down from the top", first point of aries to the right.
  200.  * always include earth.
  201.  */
  202. static
  203. watch_solarsystem (np, tminc, wbodies)
  204. Now *np;    /* time now and on each step */
  205. double tminc;    /* hrs to increment time by each step */
  206. int wbodies;
  207. {
  208.     /* max au of each planet from sun; in astro.h #defines order */
  209.     static double auscale[] = {.38, .75, 1.7, 5.2, 11., 20., 31., 50.};
  210.     double tminc0 = tminc;    /* remember the original */
  211.     /* two draw buffers so we can leave old up while calc new then
  212.      * erase and draw in one quick operation. always calc new in newp
  213.      * buffer and erase previous from lastp. buffers alternate roles.
  214.      */
  215.     LastDraw ld0[2*NOBJ], ld1[2*NOBJ], *lp, *lastp = ld0, *newp = ld1;
  216.     int nlast = 0, nnew;
  217.     int once = 1;
  218.     double lmjd;
  219.     double scale;
  220.     Sky s;
  221.     int p;
  222.  
  223.     /* set screen scale: largest au we will have to plot.
  224.      * never make it less than 1 au (with fudge) since we always show earth.
  225.      */
  226.     scale = 1.1;
  227.     for (p = MARS; p <= PLUTO; p++)
  228.         if ((wbodies & (1<<p)) && auscale[p] > scale)
  229.         scale = auscale[p];
  230.  
  231.     /* clear screen and put up the permanent labels */
  232.     c_erase();
  233.     f_string (2, 1, tznm);
  234.  
  235.     while (1) {
  236.         if (once)
  237.         print_updating();
  238.  
  239.         /* calculate desired stuff into newp[].
  240.          * fake a sun at center and add earth first.
  241.          * (we get earth's loc when ask for sun)
  242.          */
  243.         nnew = 0;
  244.         set_ss (newp+nnew, 0.0, 0.0, 0.0, 'S');
  245.         nnew += 2;
  246.         (void) body_cir (SUN, SSACC, np, &s);
  247.         set_ss (newp+nnew, s.s_edist/scale, s.s_hlong, 0.0, 'E');
  248.         nnew += 2;
  249.         for (p = MERCURY; p <= PLUTO; p++)
  250.         if (p != MOON && (wbodies & (1<<p))) {
  251.             (void) body_cir (p, SSACC, np, &s);
  252.             set_ss (newp+nnew, s.s_sdist/scale, s.s_hlong, s.s_hlat,
  253.                                 body_tags[p]);
  254.             nnew += 2;
  255.         }
  256.         for (p = OBJX; p != -1; p = (p == OBJX) ? OBJY : -1)
  257.         if (wbodies & (1<<p)) {
  258.             (void) body_cir (p, SSACC, np, &s);
  259.             if (s.s_hlong != NOHELIO && s.s_sdist <= scale) {
  260.             set_ss (newp+nnew, s.s_sdist/scale, s.s_hlong, s.s_hlat,
  261.                                 body_tags[p]);
  262.             nnew += 2;
  263.             }
  264.         }
  265.  
  266.         set_screencoords (newp, nnew);
  267.  
  268.         /* unless we want trails,
  269.          * erase any previous tags (in same order as written) from lastp[].
  270.          */
  271.         if (!trails)
  272.         for (lp = lastp; --nlast >= 0; lp++)
  273.             safe_f_char (lp->l_r, lp->l_c, ' ');
  274.  
  275.         /* print LOCAL time and date we will be using */
  276.         lmjd = mjd - tz/24.0;
  277.         f_time (2, 5, mjd_hr(lmjd));
  278.         f_date (2, 14, mjd_day(lmjd));
  279.  
  280.         /* now draw new stuff from newp[] and park the cursor */
  281.         for (lp = newp; lp < newp + nnew; lp++)
  282.         safe_f_char (lp->l_r, lp->l_c, lp->l_tag);
  283.         c_pos (PARK_ROW, PARK_COL);
  284.         fflush (stdout);
  285.  
  286.         /* swap new and last roles and save new count */
  287.         if (newp == ld0)
  288.         newp = ld1, lastp = ld0;
  289.         else
  290.         newp = ld0, lastp = ld1;
  291.         nlast = nnew;
  292.  
  293.         if (!once)
  294.         slp_sync();
  295.  
  296.         if (once || (chk_char()==0 && read_char()!=0)) {
  297.         if (readwcmd (tminc0, &tminc, &once) < 0)
  298.             break;
  299.         }
  300.  
  301.         /* advance time */
  302.         inc_mjd (np, tminc);
  303.     }
  304. }
  305.  
  306. /* fill in two LastDraw solar system entries,
  307.  * one for the x/y display, one for the z.
  308.  */
  309. static
  310. set_ss (lp, dist, lg, lt, tag)
  311. LastDraw *lp;
  312. double dist, lg, lt;    /* scaled heliocentric distance, longitude and lat */
  313. char tag;
  314. {
  315.     lp->l_fr = 0.5 - dist*sin(lg)*0.5;
  316.     lp->l_fc = 0.5 + dist*cos(lg)*0.5/ASPECT;
  317.     lp->l_tag = tag;
  318.     lp++;
  319.     /* row is to show course helio altitude but since we resolve collisions
  320.      * by adjusting columns we can get more detail by smaller variations
  321.      * within one column.
  322.      */
  323.     lp->l_fr = 0.5 - dist*sin(lt)*0.5;
  324.     lp->l_fc = c2fc(SSZCOL) + (1 - lp->l_fr)/NC;
  325.     lp->l_tag = tag;
  326. }
  327.  
  328. /* given a list of LastDraw structs with their l_{fr,fc} filled in,
  329.  * fill in their l_{r,c}.
  330.  * TODO: better collision avoidance.
  331.  */
  332. static
  333. set_screencoords (lp, np)
  334. LastDraw lp[];
  335. int np;
  336. {
  337.     LastDraw *lpi;    /* the current basis for comparison */
  338.     LastDraw *lpj;    /* the sweep over other existing cells */
  339.     int i;        /* index of the current basis cell, lpi */
  340.     int j;        /* index of sweep cell, lpj */
  341.     int n;        /* total cells placed so far (ie, # to check) */
  342.  
  343.     /* idea is to place each new item onto the screen.
  344.      * after each placement, look for collisions.
  345.      * if find a colliding pair, move the one with the greater l_fc to
  346.      * the right one cell, then rescan for more collisions.
  347.      * this will yield a result that is sorted by columns by l_fc.
  348.      * TODO: don't just move to the right, try up too for true 2d adjusts.
  349.      */
  350.     for (n = 0; n < np; n++) {
  351.         lpi = lp + n;
  352.         i = n;
  353.         lpi->l_r = fr2r(lpi->l_fr);
  354.         lpi->l_c = fc2c(lpi->l_fc);
  355.       chk:
  356.         for (j = 0; j < n; j++) {
  357.         lpj = lp + j;
  358.         if (i!=j && lpi->l_r == lpj->l_r && lpi->l_c == lpj->l_c) {
  359.             if (lpj->l_fc > lpi->l_fc) {
  360.             /* move lpj and use it as basis for checks now */
  361.             lpi = lpj;
  362.             i = j;
  363.             }
  364.             if (++lpi->l_c > NC)
  365.             lpi->l_c = 1;
  366.             goto chk;
  367.         }
  368.         }
  369.     }
  370. }
  371.  
  372. /* since the solar system scaling is only approximate, and doesn't include
  373.  * object x/y at all, characters might get mapped off screen. this funtion
  374.  * guards against drawing chars off screen. it also moves a char being drawn
  375.  * on the lower right corner of the screem left one to avoid scrolling.
  376.  */
  377. static
  378. safe_f_char (r, c, tag)
  379. int r, c;
  380. char tag;
  381. {
  382.     if (r >= 1 && r <= NR && c >= 1 && c <= NC) {
  383.         if (r == NR && c == NC)
  384.         c -= 1;
  385.         f_char (r, c, tag);
  386.     }
  387. }
  388.  
  389. /* see what the op wants to do now and update prompt/times accordingly.
  390.  * return -1 if we are finished, else 0.
  391.  */
  392. static int
  393. readwcmd (tminc0, tminc, once)
  394. double tminc0;
  395. double *tminc;
  396. int *once;
  397. {
  398.     f_prompt (qprompt);
  399.  
  400.     switch (read_char()) {
  401.     case END:         /* back to table */
  402.         return (-1);
  403.     case '\r': case ' ':    /* one StpSz step */
  404.         *tminc = tminc0;
  405.         *once = 1;
  406.         break;
  407.     case 'h':        /* one 1-hour step */
  408.         *tminc = 1.0;
  409.         *once = 1;
  410.         break;
  411.     case 'd':        /* one 24-hr step */
  412.         *tminc = 24.0;
  413.         *once = 1;
  414.         break;
  415.     case 'w':        /* 7 day step */
  416.         *tminc = 7*24.0;
  417.         *once = 1;
  418.         break;
  419.     default:        /* free-run */
  420.         *once = 0;
  421.         f_prompt (frprompt);
  422.     }
  423.     return (0);
  424. }
  425.